#!/usr/bin/env bash

# 用于 ywloader 命令行工具的补全脚本
# 
# (1)支持基本子命令的补全调试
# (2)支持基本子命令的补全能力
# (3)ywloader 命令补全主入口

# ywloader 命令调试环境变量
# 如果此环境变量被设置将会打印命令在补全时的调试信息
_ywloader_debug() {
    # 使用 BASH_COMP_YWLOADER_DEBUG_FILE 指定的文件进行输出调试信息
    #          v 如果在 bash 命令行中定义了这个环境变量，将传入本函数的所有内容输出(追加)到调试文件
    if [[ -n ${BASH_COMP_YWLOADER_DEBUG_FILE:-} ]]; then
        echo "$@" >> "${BASH_COMP_YWLOADER_DEBUG_FILE}"
    fi
}

# ywloader 命令调试文件清空函数
# 与 _ywloader_debug 不相同，且用于首次触发执行补全时清空调试文件
_ywloader_debug_clean() {
    if [[ -n ${BASH_COMP_YWLOADER_DEBUG_FILE:-} ]]; then
        echo "" > "${BASH_COMP_YWLOADER_DEBUG_FILE}"
    fi
}

# ywloader 子命令补全点

_ywloader_version() {
    # ywloader version 无需任何补全
    COMPREPLY=()
}

_ywloader_init() {
    # ywloader init 无需要任何补全
    COMPREPLY=()
}

_ywloader_add() {
    # ywloader add 可选补全: -g
    COMPREPLY=()

    # 1.在 ywloader add - 情况下直接提供补全参数
    if [[ "${cur}" == "-"* ]]; then
        COMPREPLY=( "-g" )
    fi

    # 2.在 ywloader add 情况下，不输出预期参数补全，只提供文件或目录补全
    _filedir
}

_ywloader_list() {
    # ywloader list 可选补全: -g
    COMPREPLY=()

    # 1.在 ywloader list - 情况下直接提供补全参数
    if [[ "${cur}" == "-"* ]]; then
        COMPREPLY=( "-g" )
    fi
}

_initialize_global_variable() {
    GLOBAL=
    if [[ "${words[*]}" == *" -g "* ]]; then
        GLOBAL='-g'
    fi
}

_convert_() {
    # 将所有的供选项进行添加 '' 号
    for((i=0; i<${#COMPREPLY[@]}; i++)); do
        COMPREPLY[$i]="'${COMPREPLY[i]}'"
    done
}

_ywloader_if_global() {
    if [[ "${words[*]}" == *"-g"* ]]; then
        _ywloader_debug "${words} contains: -g"
        return 0
    fi
    return 1
}

_ywloader_show() {
    # ywloader show 可选补全：-g <条目>
    COMPREPLY=()

    # 1.在 ywloader show - 情况下直接提供补全参数
    if [[ "${cur}" == "-"* ]]; then
        _ywloader_if_global || COMPREPLY=( "-g" )
        return
    fi

    GLOBAL=
    _initialize_global_variable

    # 2.在 ywloader show 任何情况下直接开始提供所有补全参数
    local IFS=$'\n'
    OPTIONS=`${binary} search ${GLOBAL} --all`
    
    # 3.最终补全内容 - 由 cur 提供判断可供选结果
    COMPREPLY=( $(compgen -W "${OPTIONS[*]}" -- ${cur}) )
    
    _convert_
}

_ywloader_use() {
    # ywloader use 可选补全：-g <条目> [条目] ...
    COMPREPLY=()
    
    # 1.在 ywloader use - 情况下直接提供补全参数
    if [[ "${cur}" == "-"* ]]; then
        _ywloader_if_global || COMPREPLY=( "-g" )
        return
    fi

    GLOBAL=
    _initialize_global_variable

    # 2.在 ywloader use 任何情况下直接开始提供所有补全参数
    local IFS=$'\n'
    OPTIONS=`${binary} search ${GLOBAL} --all`

    # 3.最终补全内容 - 由 cur 提供判断可供选结果
    COMPREPLY=( $(compgen -W "${OPTIONS[*]}" -- ${cur}) )
    
    _convert_
}

_ywloader_del() {
    # ywloader del 可选补全：-g <条目> <条目> ...
    COMPREPLY=()
}

_ywloader_change() {
    # ywloader change 可选补全：-g <条目>
    COMPREPLY=()
}

_ywloader_serve() {
    # ywloader serve 可选补全：[-p 端口号] [目录|文件]
        # 使用标准输入时:[--attachement-filename 名称] [--cache-size 缓冲区(mb)] -
    COMPREPLY=()

    FLAGS=( "-p" "--attachment-filename" "--cache-size" "--limit-speed" )

    # 1. 提供 -p 补全
    if [[ "${cur}" == "-"* ]]; then
        COMPREPLY=( $(compgen -W "${FLAGS[*]}" -- ${cur}) )
        return
    fi

    # 2. 如果上一参数非 FLAGS 项则补全文件列表路径
    case "${prev}" in
        -p|--attachment-filename|--cache-size|--limit-speed)
            COMPREPLY=()
            ;;
        *)
            _filedir
            ;;
    esac
}

_ywloader_search() {
    # ywloader search 无需补全
    COMPREPLY=()
}

_ywloader_remote() {
    # ywloader remote 预选补全
    COMPREPLY=()
}

_ywloader_cat() {
    # ywloader cat 预选补全：<条目> <指定条目内文件>
    COMPREPLY=()
}

_ywloader_update() {
    # ywloader cat 预选补全：<条目> <指定条目内文件>
    COMPREPLY=()

    # 1.在 ywloader update - 情况下直接提供补全参数
    if [[ "${cur}" == "-"* ]]; then
        _ywloader_if_global || COMPREPLY=( "-g" )
        return
    fi

    GLOBAL=
    _initialize_global_variable

    # 2.在 ywloader use 任何情况下直接开始提供所有补全参数
    local IFS=$'\n'
    OPTIONS=`${binary} search ${GLOBAL} --all`

    # 3.最终补全内容 - 由 cur 提供判断可供选结果
    COMPREPLY=( $(compgen -W "${OPTIONS[*]}" -- ${cur}) )
    _convert_

    # 4.默认补全到 index=2 ${binary} update ''
    let word_index=3
    if [[ "${GLOBAL}" == "-g" ]]; then
        # 4.如果数量超过 ${binary} update -g
        word_index=4
    fi
    
    _ywloader_debug "${cword} >= ${word_index}"
    if (( ${cword} >= ${word_index} )); then
        COMPREPLY=()
        _filedir
    fi
}

_ywloader_diff() {
    # ywloader cat 预选补全：<条目> <指定条目内文件>
    COMPREPLY=()

    # 1.在 ywloader update - 情况下直接提供补全参数
    if [[ "${cur}" == "-"* ]]; then
        _ywloader_if_global || COMPREPLY=( "-g" )
        return
    fi

    GLOBAL=
    _initialize_global_variable

    # 2.在 ywloader use 任何情况下直接开始提供所有补全参数
    local IFS=$'\n'
    OPTIONS=`${binary} search ${GLOBAL} --all`

    # 3.最终补全内容 - 由 cur 提供判断可供选结果
    COMPREPLY=( $(compgen -W "${OPTIONS[*]}" -- ${cur}) )
    _convert_


    # 4.默认补全到 index=2 ${binary} update ''
    let word_index=3
    if [[ "${GLOBAL}" == "-g" ]]; then
        # 4.如果数量超过 ${binary} update -g
        word_index=4
    fi
    
    _ywloader_debug "${cword} >= ${word_index}"
    if (( ${cword} >= ${word_index} )); then
        COMPREPLY=()
        _filedir
    fi
}

# ywloader 命令补全入口
_ywloader() {
    # 调试操作: 清空调试文件内容
    _ywloader_debug_clean

    # 1. 准备一些基本的信息，这些都是最基本的，也是在补全脚本中仅能获取的有限内容

    # 定义一些函数内变量，由 completion 驱动内置进行初始化内容
        # cur   当前的位置
        # prev  上一个词
        # words 所有词
        # cword 位置引用
    local cur prev words cword
    _init_completion || return

    # 为了更好的进行识别
        # 将第一个词标记为可执行程序名称
        # 将第二个词标记为子命令
    local binary="${words[0]}"
    local command="${words[1]}"

    _ywloader_debug "========== _ywloader function env ============"
    _ywloader_debug "_ywloader words: " "%${words[*]}%" "-- 所有词"
    _ywloader_debug "_ywloader prev:  " "%${prev}%"     "-- 前词"
    _ywloader_debug "_ywloader cur:   " "%${cur}%"      "-- 当前词"
    _ywloader_debug "_ywloader cword: " "%${cword}%"    "-- 位置引用"
    _ywloader_debug
    _ywloader_debug "_ywloader binary: " "%${binary}%"  "-- 当前程序"
    _ywloader_debug "_ywloader command:" "%${command}%" "-- 当前子命令" 
    _ywloader_debug "========== _ywloader function env ============"
    _ywloader_debug ""

# 2. 准备此命令有关的次级信息

    # 子命令集合，如果子命令不在此中，将认为尚未完成子命令的提示，可直接使用此处进行补全
    local ywloader_help_commands=(
        version init add list show use del change serve search remote 
        # 以下为預选子命令
        cat
        # 以下为后续更新命令
        update
        diff
    )

    # 子命令完整集合，包含额外的 help 命令
    local ywloader_commands=(
        help 
        ${ywloader_help_commands[*]}
    )

    COMPREPLY=()

    # 
    if [[ ${cword} == 1 ]]; then
        # _ywloader_debug "_ywloader cword: ${cword} == 1"
        if [[ "${binary}" == "ywloader" || "${binary}" == "ywloader-cli" ]]; then
            _ywloader_debug "_ywloader 可供选择:" "${ywloader_commands[*]}"
            _ywloader_debug "_ywloader 匹配前缀:" "${COMP_WORDS[1]}"
            COMPREPLY=($(compgen -W "${ywloader_commands[*]}" -- "${COMP_WORDS[1]}"))
        fi
    elif [[ ${cword} -gt 1 ]]; then 
        # _ywloader_debug "_ywloader cword: ${cword} -gt 1"
        case $command in 
            help)
                # _ywloader_${command} "${cur}" "${ywloader_help_commands[*]}"
                ;;
            version|init|add|list|show|use|del|change|serve|search|remote|cat|update|diff)
                _ywloader_debug "_ywloader 子命令 '${command}' 补全开始:"
                _ywloader_${command}
                ;;
            *)
                ;;
        esac
    fi


    _ywloader_debug "_ywloader 可用结果: ${COMPREPLY[*]}"
}

# 在 Bash 中，输入 ywloader 时，补全操作将尝试调用 _ywloader 函数尝试生成补全内容。
    # _ywloader 函数将被输入三个参数：
        # 要补全的命令名、当前光标所在的词、当前光标所在的词的前一个词
        # COMP_WORDS
        # COMP_CWORD
        # COMP_LINE
complete -F _ywloader ywloader
complete -F _ywloader ywloader-cli


# compgen：
# 用法：compgen [-abcdefgjksuv] [-o 选项]  [-A 动作] [-G 全局模式] [-W 词语列表]  [-F 函数] [-C 命令] [-X 过滤模式] [-P 前缀] [-S 后缀] [词语]
    # -W wordlist
        # wordlist 被使用 IFS 特殊变量中的字符作为定界符来拆分，每个结果的词被扩展。可能的补全是结果列表 中匹配要补全的词的那一些。

# 在 Bash 中，借助 compgen 强大的可用函数列表、命令、词语列表输出能力，即可生成最终补全内容
    # 例如从一组词语中进行补全匹配，即可得到结果：补全 j 在提供的 词语列表 中可能匹配的补全
        # $ compgen -W "c++ java json rust" -- j
    # 则会输出以下内容
        # java
        # json